package com.swipemaster.levels;

import com.swipemaster.activities.CustomGameActivity;
import com.swipemaster.common.Bitmaps;
import com.swipemaster.common.Const;
import com.swipemaster.common.CustomGameSettings;
import com.swipemaster.common.Global;
import com.swipemaster.elements.Circle;
import com.swipemaster.elements.Rectangle;
import com.swipemaster.elements.Snake;
import com.swipemaster.moves.CircleMove;
import com.swipemaster.moves.FreeMove;
import com.swipemaster.moves.NoMove;
import com.swipemaster.moves.PathMove;
import com.swipemaster.moves.PlayerMove;

/** Class which generates levels. Don't create instance of this factory, just call its public methods. */
public class LevelFactory
{
	public static final int CUSTOM_GAME_SPAWN_PERIOD = 1;
	private static LevelHolder[] levelHolders;

	public static SurvivalLevel getCustomGameLevel()
	{
		final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer());
		final int speedUpTimes[] =
		{ 20, 40, 60 };
		survivalLevel.setSpeedUpTimes(speedUpTimes);
		final double enemiesRadiusPx = CustomGameActivity.getEnemiesPx(CustomGameSettings.enemiesSize);
		survivalLevel.setEnemySpawn(CUSTOM_GAME_SPAWN_PERIOD, CustomGameSettings.numberOfEnemies, enemiesRadiusPx
				/ Global.app.consts.diagonal);
		survivalLevel.setBouncing(CustomGameSettings.bouncing);
		survivalLevel.setParticlesActive(CustomGameSettings.particles);
		return survivalLevel;
	}

	/** Returns a level object. In the first call, it will prepare all the level holders.
	 * @return Ready-to-use level object found with given level index. */
	public static Level getLevel(int index)
	{
		if (levelHolders == null)
		{
			setLevelHolders();
		}
		return levelHolders[index].getLevel();
	}

	public static SurvivalLevel getSurvivalModeLevel()
	{
		final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer());
		survivalLevel.setEnemySpawn(10, 6, Const.RADIUS);
		survivalLevel.setBouncing(true);
		return survivalLevel;
	}

	/** @return Standard element for player, which should look the same or very similar among all levels. */
	private static Circle getPlayer()
	{
		return new Circle(0.5, 0.95, new PlayerMove(), Const.RADIUS);
	}

	/** @return Standard element for pleyer with custom radious scale */
	private static Circle getPlayer(double scale)
	{
		return new Circle(0.5, 0.95, new PlayerMove(), Const.RADIUS * scale);
	}

	private static Circle getPlayer(double x, double y)
	{
		return new Circle(x, y, new PlayerMove(), Const.RADIUS);
	}

	/** @param x Horizontal center of finish. Universal units.
	 * @param width Width of finish. Universal units.
	 * @return Standard finish line placed on top of the screen. */
	private static Rectangle getStandardFinish()
	{
		return new Rectangle(0, 0, 1, 0.07, new NoMove(), Bitmaps.finishTile);
	}

	/** Here we can write code for all levels. Level indices are 0-based. */
	private static void setLevelHolders()
	{
		levelHolders = new LevelHolder[Const.LEVELS];

		final int survivalLevels[] = new int[Const.LEVELS];
		for (int i = 0; i < Const.LEVELS; i++)
		{
			survivalLevels[i] = -1;
		}
		int survCount = 0;

		final boolean wallCollision[] = new boolean[Const.LEVELS];
		for (int i = 0; i < wallCollision.length; i++)
		{
			wallCollision[i] = true;
		}
		final int speedUpTimes[][] = new int[Const.LEVELS][];
		final boolean bouncingTable[] = new boolean[Const.LEVELS];
		final int enemiesTable[] = new int[Const.LEVELS];
		final int spawnPeriodsTable[] = new int[Const.LEVELS];
		final int secondsTable[][] = new int[4][Const.LEVELS];
		final double radiousTable[] = new double[Const.LEVELS];
		final double radiousSizes[] =
		{ 0.5, 0.675, 0.85, 1.025, 1.2 };
		int index = 0;

		for (int i = 0; i < radiousSizes.length; i++)
		{
			radiousSizes[i] *= Const.RADIUS;
		}

		for (int i = 0; i < Const.LEVELS; i++)
		{
			levelHolders[i] = new LevelHolder()
			{
				@Override
				public Level getLevel()
				{
					final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 30, 35);
					survivalLevel.setEnemySpawn(2, 3, Const.RADIUS * 0.8);
					survivalLevel.setBouncing(true);
					survivalLevel.setWallCollision(false);
					return survivalLevel;
				}
			};
		}

		{
			index = 0;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			wallCollision[index] = true;
			enemiesTable[index] = 2;
			radiousTable[index] = radiousSizes[3];
			spawnPeriodsTable[index] = 3;
			secondsTable[0][index] = 10;
			secondsTable[1][index] = 15;
			secondsTable[2][index] = 30;
			secondsTable[3][index] = 45;
			final int times[] =
			{ 10, 20, 30 };
			speedUpTimes[index] = times;
		}

		index = 1;
		// 3 kolka biegajace poziomo z meta na gorze.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.5, 0.95, new PlayerMove(), Const.RADIUS);

				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 7, 3, 1);
				{
					final double targets[] =
					{ 0.9, 0.25, 0.1, 0.25 };
					final Circle enemy = new Circle(0.5, 0.25, new PathMove(targets, Const.MAX_SPEED), radiousSizes[3]);
					puzzleLevel.addEnemy(enemy);
				}
				{
					final double targets[] =
					{ 0.1, 0.5, 0.9, 0.5 };
					final Circle enemy = new Circle(0.1, 0.5, new PathMove(targets, Const.MAX_SPEED), radiousSizes[3]);
					puzzleLevel.addEnemy(enemy);
				}
				{
					final double targets[] =
					{ 0.1, 0.75, 0.9, 0.75 };
					final Circle enemy = new Circle(0.5, 0.75, new PathMove(targets, Const.MAX_SPEED), radiousSizes[3]);
					puzzleLevel.addEnemy(enemy);
				}
				return puzzleLevel;
			}
		};

		{
			index = 2;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			wallCollision[index] = false;
			enemiesTable[index] = 3;
			radiousTable[index] = radiousSizes[4];
			spawnPeriodsTable[index] = 3;
			secondsTable[0][index] = 15;
			secondsTable[1][index] = 20;
			secondsTable[2][index] = 30;
			secondsTable[3][index] = 40;
			final int times[] =
			{ 15, 30 };
			speedUpTimes[index] = times;
		}

		index = 3;
		// Proste dwójki.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.05, 0.95, new PlayerMove(), radiousSizes[2]);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 10, 6, 3);
				Circle circle;

				// Bottom wall.
				final Rectangle bottomWall = new Rectangle(0, 0.536, 0.55, 0.764, new NoMove(), Bitmaps.wallTile);
				puzzleLevel.addEnemy(bottomWall);

				// Upper wall.
				final Rectangle upperWall = new Rectangle(0.35, 0.236, 1, 0.364, new NoMove(), Bitmaps.wallTile);
				puzzleLevel.addEnemy(upperWall);

				// Bottom enemies.
				final double targets3[] =
				{ 0.25, 0.7, 0.25, 0.95, };
				circle = new Circle(0.25, 0.7, new PathMove(targets3, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets2[] =
				{ 0.46, 0.7, 0.46, 0.95, };
				circle = new Circle(0.46, 0.95, new PathMove(targets2, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				// Upper enemies.
				final double targets6[] =
				{ 0.45, 0.1, 0.45, 0.55, };
				circle = new Circle(0.46, 0.1, new PathMove(targets6, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets5[] =
				{ 0.65, 0.1, 0.65, 0.55, };
				circle = new Circle(0.65, 0.65, new PathMove(targets5, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				return puzzleLevel;
			}
		};

		index = 4;
		// Spadające kółka.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(1.1), 20, 25, 35, 50);
				final int times[] =
				{ 15, 35, 50, 80 };
				survivalLevel.setSpeedUpTimes(times);

				double speed = Const.MAX_SPEED * 0.85;

				for (int i = 0; i < 4; i++)
				{
					final double targets[] =
					{ 0.1 + (i * 0.25), -0.1, 0.1 + (i * 0.25), 1.1 };
					final PathMove pm1 = new PathMove(targets, speed);
					pm1.setModuloMove(true);
					final Circle circle = new Circle(0.1 + (i * 0.25), -0.1 - (i * 0.4), pm1, Const.RADIUS * 0.8);
					survivalLevel.addEnemy(circle);
				}
				for (int i = 0; i < 4; i++)
				{
					final double targets[] =
					{ 0.1 + (i * 0.25), -0.4, 0.1 + (i * 0.25), 1.1 };
					final PathMove pm1 = new PathMove(targets, speed);
					pm1.setModuloMove(true);
					final Circle circle = new Circle(0.1 + (i * 0.25), -0.1 - (i * 0.4), pm1, Const.RADIUS * 0.8);
					survivalLevel.addEnemy(circle);
				}
				for (int i = 0; i < 4; i++)
				{
					if ((i == 3) || (i == 1))
					{
						continue;
					}
					final double targets[] =
					{ 0.1 + (i * 0.25), -0.8, 0.1 + (i * 0.25), 1.1 };
					final PathMove pm1 = new PathMove(targets, speed);
					pm1.setModuloMove(true);
					final Circle circle = new Circle(0.1 + (i * 0.25), -0.1 - (i * 0.4), pm1, Const.RADIUS * 0.8);
					survivalLevel.addEnemy(circle);
				}

				return survivalLevel;
			}
		};

		index = 5;
		// Ośmiorniczka.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(0.5, 0.58), 20, 25, 40, 60);
				final int times[] =
				{ 10, 20, 25, 40 };
				survivalLevel.setSpeedUpTimes(times);

				int angle = 0;
				for (int i = 0; i < 5; i++)
				{
					for (int j = 0; j < 9; j++)
					{
						if ((i == 1) && ((j == 3) || (j == 4)))
						{
							continue;
						}
						if ((i == 0) && ((j == 7) || (j == 8)))
						{
							continue;
						}
						if ((i == 3) && ((j == 5) || (j == 6)))
						{
							continue;
						}
						if ((i == 2) && ((j == 2) || (j == 3)))
						{
							continue;
						}
						if ((i == 4) && ((j == 6) || (j == 7)))
						{
							continue;
						}

						if ((i != 4) && (j == 8))
						{
							continue;
						}
						final CircleMove circleMove = new CircleMove(0.5, 0.23, j * 0.085, 0.06, angle);
						final Circle circle = new Circle(circleMove);
						survivalLevel.addEnemy(circle);
					}
					if ((i % 2) == 0)
					{
						angle += 72;
					}
					else if (i == 3)
					{
						angle -= 144;
					}
					else
					{
						angle += 144;
					}
				}

				return survivalLevel;
			}
		};

		index = 6;
		// Wskazówka zegarowa + wężyk.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 35, 45);
				final int times[] =
				{ 15, 30 };
				survivalLevel.setSpeedUpTimes(times);

				for (int j = 0; j < 7; j++)
				{
					final CircleMove circleMove = new CircleMove(0.5, 0.5, j * 0.075, 0.13, 180);
					final Circle circle = new Circle(circleMove);
					survivalLevel.addEnemy(circle);
				}

				double x = 0;
				final double r = 0.02;
				final Snake snake = new Snake(8);
				survivalLevel.addEnemy(snake);
				x += 0.5;
				for (int i = 6; i >= 1; i--)
				{
					final double[] targets =
					{ 0.25, 0.9 };
					final Circle circle = new Circle(x, i * 2 * r * Global.app.consts.dth, new PathMove(targets,
							Const.MAX_SPEED * 0.65), r);
					snake.addSnakeElement(circle);
				}

				return survivalLevel;
			}
		};

		index = 7;
		// Strzelające z środka.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.5, 0.9, new PlayerMove(), Const.RADIUS);
				final SurvivalLevel survivalLevel = new SurvivalLevel(player, 15, 20, 30, 50);
				final int times[] =
				{ 25, 50 };
				survivalLevel.setSpeedUpTimes(times);

				final double radius = 1.2;
				final int howMany = 17;
				int angle = 0;
				final int step = 360 / howMany;
				for (int j = 0; j < howMany; j++)
				{
					final double x = 0.5 + (Math.cos((Math.PI * angle) / 180) * radius);
					final double y = 0.5 + (Math.sin((Math.PI * angle) / 180) * radius);
					angle += 3 * step;
					angle %= 360;
					final double targets[] =
					{ 0.5, 0.36, x, y };
					final PathMove pathMove = new PathMove(targets, Const.MAX_SPEED * 0.65);
					pathMove.setModuloMove(true);
					final int k = j / 2;
					final Circle circle = new Circle(0.5, 0 - (k * 0.4), pathMove, Const.RADIUS * 0.5);
					survivalLevel.addEnemy(circle);
				}
				Circle circle = new Circle(0, 0, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);
				circle = new Circle(1, 0, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);
				circle = new Circle(1, 1, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);
				circle = new Circle(0, 1, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);

				final double[] targets1 =
				{ 0.1, 0.08, 0.1, 0.92, 0.9, 0.92, 0.9, 0.08 };
				final PathMove pathMove = new PathMove(targets1, Const.MAX_SPEED);
				circle = new Circle(0.5, 0.5, pathMove, radiousSizes[4]);
				survivalLevel.addEnemy(circle);

				return survivalLevel;
			}
		};

		{
			index = 8;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[0];
			spawnPeriodsTable[index] = 3;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 35;
			secondsTable[3][index] = 50;
			final int times[] =
			{ 25, 50 };
			speedUpTimes[index] = times;
		}

		index = 9;
		// Survival, ale wężykiem.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 35, 50);
				survivalLevel.setEnemySpawn(4, 3, radiousSizes[1]);
				final int times[] =
				{ 25, 40 };
				survivalLevel.setSpeedUpTimes(times);

				double x = 0;
				final double r = 0.02;
				final Snake snake = new Snake(8);
				survivalLevel.addEnemy(snake);
				x += 0.5;
				for (int i = 7; i >= 1; i--)
				{
					final double[] targets =
					{ 0.25, 0.9 };
					final Circle circle = new Circle(x, i * 2 * r * Global.app.consts.dth, new PathMove(targets,
							Const.MAX_SPEED * 0.6), r);
					snake.addSnakeElement(circle);
				}
				return survivalLevel;
			}
		};

		{
			index = 10;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 1;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 50;
			final int times[] =
			{ 25, 45 };
			speedUpTimes[index] = times;
		}

		index = 11;
		// Małe pętelki.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final double circlesSpeed = 0.3;

				final double noMoveRadious = Const.RADIUS * 1.45;

				final Circle player = new Circle(0.05, 0.95, new PlayerMove(), Const.RADIUS);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 15, 8, 4);

				Circle circle;
				// upper no - moves
				circle = new Circle(0.353333, 0.25, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.62, 0.25, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.87, 0.25, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.873333, 0.405, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);

				// botton no - moves
				circle = new Circle(0.63, 0.745, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.37, 0.65, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.11, 0.65, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.11, 0.745, new NoMove(), noMoveRadious);
				puzzleLevel.addEnemy(circle);

				circle = new Circle(0.2, 0.45, new CircleMove(0.17, 0.45, 0.08, circlesSpeed, 0));
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.7, 0.45, new CircleMove(0.6, 0.45, 0.08, circlesSpeed, 180, Const.LEFT));
				puzzleLevel.addEnemy(circle);

				// bottom circling
				circle = new Circle(0.376667, 0.8875, new CircleMove(0.376667, 0.8875, 0.08, circlesSpeed, 0));
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.856667, 0.89, new CircleMove(0.856667, 0.89, 0.09, circlesSpeed, 0));
				puzzleLevel.addEnemy(circle);

				return puzzleLevel;
			}
		};

		{
			index = 12;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			wallCollision[index] = false;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 50;
			final int times[] =
			{ 25, 45 };
			speedUpTimes[index] = times;
		}

		index = 13;
		// Gąsienice.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Rectangle finish = new Rectangle(0.5, 0.5, new NoMove(), 0.08, 0.08, Bitmaps.finishTile);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(getPlayer(), finish, 10, 5, 3);

				final int wallRight = (int) (((0.95 + 0.5) * Global.app.consts.htd) / 0.08);
				final int wallUp = (int) (((1 - 0.2 - 0.04) * Global.app.consts.wtd) / 0.08);
				final int wallLeft = (int) ((0.5 * Global.app.consts.htd) / 0.08);
				final double speed = 0.0005;

				final double targets[] =
				{ 0.9, 0.05, 0.1, 0.05, 0.1, 0.95, 0.9, 0.95 };
				for (int i = 0; i < wallRight; i++)
				{
					final Circle enemy = new Circle(0.9, 0.05 + ((i * 0.08) / Global.app.consts.htd), new PathMove(
							targets, speed));
					puzzleLevel.addEnemy(enemy);
				}
				final double targets2[] =
				{ 0.1, 0.05, 0.1, 0.95, 0.9, 0.95, 0.9, 0.05 };
				for (int i = 0; i < wallUp; i++)
				{
					final Circle enemy = new Circle(0.9 - (0.08 / Global.app.consts.wtd)
							- ((i * 0.08) / Global.app.consts.wtd), 0.05, new PathMove(targets2, speed));
					puzzleLevel.addEnemy(enemy);
				}
				final double targets3[] =
				{ 0.1, 0.95, 0.9, 0.95, 0.9, 0.05, 0.1, 0.05 };
				for (int i = 0; i < wallLeft; i++)
				{
					final Circle enemy = new Circle(0.1, 0.05 + (0.08 / Global.app.consts.htd)
							+ ((i * 0.08) / Global.app.consts.htd), new PathMove(targets3, speed));
					puzzleLevel.addEnemy(enemy);
				}

				final double targets4[] =
				{ 0.25, 0.75, 0.75, 0.75, 0.75, 0.25, 0.25, 0.25 };
				for (int i = 0; i < 15; i++)
				{
					final Circle enemy = new Circle(0.25 + ((i * 0.06) / Global.app.consts.wtd), 0.75, new PathMove(
							targets4, speed), 0.03);
					puzzleLevel.addEnemy(enemy);
				}

				final Circle enemy = new Circle(0.5, 0.5, new CircleMove(0.5, 0.5, 0.1, 0.24));
				puzzleLevel.addEnemy(enemy);

				final Circle enemy2 = new Circle(0.5, 0.5, new CircleMove(0.5, 0.5, 0.1, 0.24, 0, Const.LEFT));
				puzzleLevel.addEnemy(enemy2);

				return puzzleLevel;
			}
		};

		{
			index = 14;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			wallCollision[index] = false;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[4];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 35;
			secondsTable[3][index] = 45;
			final int times[] =
			{ 25, 50 };
			speedUpTimes[index] = times;
		}

		index = 15;
		// Dzikie węże.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 35, 45);

				final double[] targets1 =
				{ 0.1, 0.05, 0.1, 0.95, 0.9, 0.95, 0.9, 0.05 };
				final PathMove pathMove = new PathMove(targets1, Const.MAX_SPEED * 0.5);

				final Circle circle1 = new Circle(0.5, 0.5, pathMove, radiousSizes[3]);
				survivalLevel.addEnemy(circle1);

				double x = 0;
				final double r = 0.02;
				for (int j = 0; j < 5; j++)
				{
					final Snake snake = new Snake(8);
					survivalLevel.addEnemy(snake);
					x += 0.16;
					for (int i = 7; i >= 1; i--)
					{
						final double[] targets =
						{ 0.25, 0.9 };
						final Circle circle = new Circle(x, i * 2 * r * Global.app.consts.dth, new PathMove(targets,
								Const.MAX_SPEED * 0.6), r);
						snake.addSnakeElement(circle);
					}
				}

				return survivalLevel;
			}
		};
		{
			index = 16;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[4];
			spawnPeriodsTable[index] = 3;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 35;
			secondsTable[3][index] = 50;
			final int times[] =
			{ 25, 50 };
			speedUpTimes[index] = times;
		}

		index = 17;
		// Dwie kręcącie się pętle.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.5, 0.8, new PlayerMove(), Const.RADIUS);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 10, 6, 3);
				Circle circle;

				// Bottom loop.
				for (int i = 0; i < 12; i++)
				{
					final double targets[] =
					{ 0.9, 0.5625, 0.9, 0.95, 0.1, 0.95, 0.1, 0.5625, };
					circle = new Circle(0.85 - (i * 4.88 * Const.RADIUS), 0.5625, new PathMove(targets,
							Const.MAX_SPEED * 0.8));
					puzzleLevel.addEnemy(circle);
				}

				// Single one in the middle.
				final double targets1[] =
				{ -0.1, 0.43, 1.1, 0.43, };
				final PathMove pathMove = new PathMove(targets1, Const.MAX_SPEED * 0.7);
				pathMove.moduloMove = true;
				final Circle circleMiddle = new Circle(-0.1, 0.43, pathMove);
				puzzleLevel.addEnemy(circleMiddle);

				// Upper loop.
				for (int i = 0; i < 9; i++)
				{
					final double targets[] =
					{ 0.9, 0.05, 0.9, 0.3, 0.1, 0.3, 0.1, 0.05, };
					circle = new Circle(0.85 - (i * 5.05 * Const.RADIUS), 0.05, new PathMove(targets,
							Const.MAX_SPEED * 0.8));
					puzzleLevel.addEnemy(circle);
				}

				return puzzleLevel;
			}
		};

		{
			index = 18;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			wallCollision[index] = true;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[1];
			spawnPeriodsTable[index] = 1;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 45;
			secondsTable[3][index] = 60;
			final int times[] =
			{ 25, 45 };
			speedUpTimes[index] = times;
		}

		index = 19;
		// Level a'la PacMan.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(0.85), 20, 25, 35, 50);
				final int blocks = 4;
				final double blockHeight = 0.04;
				final double gap = (1 - (blocks * blockHeight)) / (blocks + 1);

				for (int i = 0; i < blocks; i++)
				{
					final Rectangle rect = new Rectangle(0.5, (i * blockHeight) + ((i + 1) * gap) + (blockHeight / 2),
							new NoMove(), 0.5, 0.04, Bitmaps.wallTile);
					survivalLevel.addEnemy(rect);
				}

				double speed = Const.MAX_SPEED * 0.65;
				final double targets1[] =
				{ 0.1, 0.05, 0.9, 0.05, 0.9, 0.95, 0.1, 0.95 };
				final Circle circle1 = new Circle(new PathMove(targets1, speed), Const.RADIUS * 0.6);
				survivalLevel.addEnemy(circle1);

				final double targets2[] =
				{ 0.1, 0.294, 0.9, 0.294, 0.9, 0.706, 0.1, 0.706 };
				final Circle circle2 = new Circle(new PathMove(targets2, speed), Const.RADIUS * 0.6);
				survivalLevel.addEnemy(circle2);

				final double targets3[] =
				{ 0.1, 0.05, 0.9, 0.05, 0.9, 0.5, 0.1, 0.5 };
				final Circle circle3 = new Circle(new PathMove(targets3, speed), Const.RADIUS * 0.6);
				survivalLevel.addEnemy(circle3);

				final double targets4[] =
				{ 0.1, 0.5, 0.1, 0.95, 0.9, 0.95, 0.9, 0.5 };
				final Circle circle4 = new Circle(new PathMove(targets4, speed), Const.RADIUS * 0.6);
				survivalLevel.addEnemy(circle4);

				return survivalLevel;
			}
		};

		{
			index = 20;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			wallCollision[index] = false;
			enemiesTable[index] = 5;
			radiousTable[index] = radiousSizes[4];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 35;
			secondsTable[3][index] = 50;
			final int times[] =
			{ 30 };
			speedUpTimes[index] = times;
		}

		index = 21;
		// Kółka biegające od lewej do prawej, meta na górze.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.5, 0.95, new PlayerMove(), Const.RADIUS * 0.92);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 8, 5, 3);
				for (int y = 1; y <= 8; y++)
				{
					final double targets[] =
					{ 0.1, 0.1 * y, 0.9, 0.1 * y };
					int x = 0;
					double yPos = 0;
					if ((y % 2) == 0)
					{
						x = 1;
						yPos -= y * 0.05;
					}
					final Circle enemy = new Circle(x, yPos, new PathMove(targets, Const.MAX_SPEED), radiousSizes[2]);
					puzzleLevel.addEnemy(enemy);
				}

				for (int x = 1; x <= 3; x++)
				{
					final double targets[] =
					{ 0.9, 0.15, 10, 0.1 };
					final Circle enemy = new Circle(0.9, 0.1 + (x * 0.25), new PathMove(targets, Const.MAX_SPEED * 0.5));
					puzzleLevel.addEnemy(enemy);
				}

				return puzzleLevel;
			}
		};

		{
			index = 22;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			enemiesTable[index] = 4;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 1;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 55;
			final int times[] =
			{ 25, 45 };
			speedUpTimes[index] = times;
		}

		index = 23;
		// Kółka lecące od prawej do lewej, ich wysokości są losowane.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.05, 0.5, new PlayerMove(), Const.RADIUS * 0.8);
				final SurvivalLevel survivalLevel = new SurvivalLevel(player, 25, 30, 45, 60);
				final int times[] =
				{ 30, 50 };
				survivalLevel.setSpeedUpTimes(times);

				for (int i = 0; i < 10; i++)
				{
					final double y = Math.random();
					final double targets[] =
					{ -0.1, y, 1.1, y };
					final PathMove pathMove = new PathMove(targets, Const.MAX_SPEED / 2);
					pathMove.setModuloMove(true);
					final Circle circle = new Circle(1 + (0.1 * i), y, pathMove, Const.RADIUS * 0.8);
					survivalLevel.addEnemy(circle);
				}

				final double targets[] =
				{ 1.1, 0.05, -0.1, 0.05 };
				PathMove pathMove = new PathMove(targets, Const.MAX_SPEED / 2);
				pathMove.setModuloMove(true);
				Circle circle = new Circle(1 + 0.1, 0.05, pathMove, Const.RADIUS * 0.8);
				survivalLevel.addEnemy(circle);

				final double targets2[] =
				{ 1.1, 0.95, -0.1, 0.95 };
				pathMove = new PathMove(targets2, Const.MAX_SPEED / 2);
				pathMove.setModuloMove(true);
				circle = new Circle(1 + 0.2, 0.95, pathMove, Const.RADIUS * 0.8);
				survivalLevel.addEnemy(circle);

				circle = new Circle(0.75, 0.8, new FreeMove(Const.MAX_SPEED * 0.8, Const.MAX_SPEED * 0.85,
						survivalLevel));
				survivalLevel.addEnemy(circle);

				return survivalLevel;
			}
		};

		{
			index = 24;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			enemiesTable[index] = 5;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 60;
			final int times[] =
			{ 30, 55 };
			speedUpTimes[index] = times;
		}

		index = 25;
		// Dwójki.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.05, 0.95, new PlayerMove(), radiousSizes[2]);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 13, 8, 5);
				Circle circle;

				// Bottom wall.
				final Rectangle bottomWall = new Rectangle(0, 0.536, 0.55, 0.764, new NoMove(), Bitmaps.wallTile);
				puzzleLevel.addEnemy(bottomWall);

				// Upper wall.
				final Rectangle upperWall = new Rectangle(0.35, 0.236, 1, 0.364, new NoMove(), Bitmaps.wallTile);
				puzzleLevel.addEnemy(upperWall);

				// Bottom enemies.
				final double targets3[] =
				{ 0.25, 0.7, 0.25, 0.95, };
				circle = new Circle(0.25, 0.7, new PathMove(targets3, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets2[] =
				{ 0.46, 0.7, 0.46, 0.95, };
				circle = new Circle(0.46, 0.95, new PathMove(targets2, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets1[] =
				{ 0.65, 0.95, 0.65, 0.65, };
				circle = new Circle(0.65, 0.6, new PathMove(targets1, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				// Upper enemies.
				final double targets7[] =
				{ 0.25, 0.55, 0.25, 0.1, };
				circle = new Circle(0.25, 0.55, new PathMove(targets7, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets6[] =
				{ 0.45, 0.1, 0.45, 0.55, };
				circle = new Circle(0.46, 0.1, new PathMove(targets6, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets5[] =
				{ 0.65, 0.1, 0.65, 0.55, };
				circle = new Circle(0.65, 0.325, new PathMove(targets5, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				final double targets8[] =
				{ 0.85, 0.55, 0.85, 0.1, };
				circle = new Circle(0.85, 0.325, new PathMove(targets8, Const.MAX_SPEED / 2));
				puzzleLevel.addEnemy(circle);

				return puzzleLevel;
			}
		};

		{
			index = 26;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			enemiesTable[index] = 5;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 60;
			final int times[] =
			{ 30 };
			speedUpTimes[index] = times;
		}

		// Survival, ale z 1 ścianą.
		index = 27;
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 35, 50);
				survivalLevel.setEnemySpawn(3, 4, radiousSizes[2]);
				final int times[] =
				{ 35 };
				survivalLevel.setSpeedUpTimes(times);

				final double[] targets =
				{ 0.1, 0.5, 0.9, 0.5 };
				final Rectangle rect = new Rectangle(0.1, 0.5, new PathMove(targets, Const.MAX_SPEED), 0.2, 0.1,
						Bitmaps.wallTile);
				survivalLevel.addEnemy(rect);

				return survivalLevel;
			}
		};

		{
			index = 28;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			wallCollision[index] = false;
			enemiesTable[index] = 5;
			radiousTable[index] = radiousSizes[3];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 30;
			secondsTable[3][index] = 40;
			final int times[] =
			{ 25, 55 };
			speedUpTimes[index] = times;
		}

		index = 29;
		// Przeplatanka.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.3, 0.95, new PlayerMove(), radiousSizes[2]);
				final PuzzleLevel puzzleLevel = new PuzzleLevel(player, getStandardFinish(), 12, 7, 4);
				for (int i = 0; i < 3; i++)
				{
					final double targets[] =
					{ 0.1, 0.1 + (0.3 * i), 0.9, 0.1 + (0.3 * i) };
					Circle circle = new Circle(0.9, 0.1 + (0.3 * i), new PathMove(targets, Const.MAX_SPEED),
							Const.RADIUS * 0.8);
					puzzleLevel.addEnemy(circle);

					final double targets2[] =
					{ 0.1, 0.2 + (0.3 * i), 0.9, 0.2 + (0.3 * i) };
					circle = new Circle(0.1, 0.2 + (0.3 * i), new PathMove(targets2, Const.MAX_SPEED),
							Const.RADIUS * 0.8);
					puzzleLevel.addEnemy(circle);
				}

				for (int i = 0; i < 3; i++)
				{
					final double targets[] =
					{ 0.1 + (0.4 * i), 0.1, 0.1 + (0.4 * i), 0.9 };
					final Circle circle = new Circle(0.1 + (0.4 * i), 0.1, new PathMove(targets, Const.MAX_SPEED),
							Const.RADIUS * 0.8);
					puzzleLevel.addEnemy(circle);
				}

				return puzzleLevel;
			}
		};

		{
			index = 30;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			wallCollision[index] = true;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[0];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 35;
			secondsTable[2][index] = 50;
			secondsTable[3][index] = 70;
			final int times[] =
			{ 30, 55 };
			speedUpTimes[index] = times;
		}

		index = 31;
		// 6 wiatraczków.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(0.9, 0.95), 20, 25, 35, 50);
				final int times[] =
				{ 30 };
				survivalLevel.setSpeedUpTimes(times);
				final double r = 0.02;
				for (int j = 0; j < 5; j++)
				{
					final CircleMove circleMove = new CircleMove(0.7, 0.7, j * 0.05, 0.18, 270);
					final Circle circle = new Circle(circleMove, r);
					survivalLevel.addEnemy(circle);
				}
				for (int j = 0; j < 5; j++)
				{
					final CircleMove circleMove = new CircleMove(0.5, 0.7, j * 0.05, 0.18, 180);
					final Circle circle = new Circle(circleMove, r);
					survivalLevel.addEnemy(circle);
				}
				for (int j = 0; j < 5; j++)
				{
					final CircleMove circleMove = new CircleMove(0.3, 0.7, j * 0.05, 0.18, 90);
					final Circle circle = new Circle(circleMove, r);
					survivalLevel.addEnemy(circle);
				}
				for (int j = 0; j < 5; j++)
				{
					final CircleMove circleMove = new CircleMove(0.3, 0.3, j * 0.05, 0.18, 90, Const.LEFT);
					final Circle circle = new Circle(circleMove, r);
					survivalLevel.addEnemy(circle);
				}
				for (int j = 0; j < 5; j++)
				{
					final CircleMove circleMove = new CircleMove(0.5, 0.3, j * 0.05, 0.18, 130, Const.LEFT);
					final Circle circle = new Circle(circleMove, r);
					survivalLevel.addEnemy(circle);
				}
				for (int j = 0; j < 5; j++)
				{
					final CircleMove circleMove = new CircleMove(0.7, 0.3, j * 0.05, 0.18, 190, Const.LEFT);
					final Circle circle = new Circle(circleMove, r);
					survivalLevel.addEnemy(circle);
				}

				final double targets[] =
				{ 0.9, 0.5, 0.9, 0.95, 0.1, 0.95, 0.1, 0.5, 0.9, 0.5, 0.9, 0.05, 0.1, 0.05, 0.1, 0.5 };
				final PathMove pathMove = new PathMove(targets, Const.MAX_SPEED);
				final Circle pathCircle = new Circle(0.5, 0.5, pathMove);
				survivalLevel.addEnemy(pathCircle);

				return survivalLevel;
			}
		};

		{
			index = 32;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[1];
			spawnPeriodsTable[index] = 1;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 55;
			final int times[] =
			{ 35 };
			speedUpTimes[index] = times;
		}

		{
			index = 33;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			wallCollision[index] = false;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[1];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 30;
			secondsTable[3][index] = 40;
			final int times[] =
			{ 30 };
			speedUpTimes[index] = times;
		}

		index = 34;
		// Survival, z dużym wężem.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 30, 40, 50);
				survivalLevel.setEnemySpawn(4, 4, radiousSizes[1]);
				final int times[] =
				{ 25, 40 };
				survivalLevel.setSpeedUpTimes(times);

				double x = 0;
				final double r = 0.05;
				final int LENGTH = 6;
				final Snake snake = new Snake(LENGTH);
				survivalLevel.addEnemy(snake);
				x += 0.5;
				for (int i = LENGTH - 1; i >= 1; i--)
				{
					final double[] targets =
					{ 0.25, 0.9 };
					final Circle circle = new Circle(x, i * 2 * r * Global.app.consts.dth, new PathMove(targets,
							Const.MAX_SPEED * 0.6), r);
					snake.addSnakeElement(circle);
				}
				return survivalLevel;
			}
		};

		{
			index = 35;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = false;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[1];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 50;
			final int times[] =
			{ 25, 50 };
			speedUpTimes[index] = times;
		}

		index = 36;
		// Wszystkie typy ruchów.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 30, 35);
				final int times[] =
				{ 25, 50 };
				survivalLevel.setSpeedUpTimes(times);
				survivalLevel.setBouncing(false);
				Circle circle;

				circle = new Circle(0.5, 0.485, new CircleMove(0.5, 0.46, 0.3, 0.27));
				survivalLevel.addEnemy(circle);

				circle = new Circle(0.09, 0.4875, new FreeMove(Const.MAX_SPEED, Const.MAX_SPEED, survivalLevel));
				survivalLevel.addEnemy(circle);

				final double targets1[] =
				{ 0.95, 0.5, 0.5, 0.95, 0.05, 0.5, 0.5, 0.05, };
				circle = new Circle(0.95, 0.5, new PathMove(targets1, Const.MAX_SPEED));
				survivalLevel.addEnemy(circle);

				final double targets2[] =
				{ 0.05, 0.05, 0.05, 0.95, 0.95, 0.95, 0.95, 0.05, };
				circle = new Circle(0.95, 0.05, new PathMove(targets2, Const.MAX_SPEED));
				survivalLevel.addEnemy(circle);

				return survivalLevel;
			}
		};

		{
			index = 37;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			wallCollision[index] = false;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 3;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 30;
			secondsTable[3][index] = 40;
			final int times[] =
			{ 30 };
			speedUpTimes[index] = times;
		}

		index = 38;
		// 3 wskazowki zegarowe - trudne ale b. ciekawe
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(0.9), 20, 40, 60, 90);
				final int times[] =
				{ 10, 25, 55 };
				survivalLevel.setSpeedUpTimes(times, 1.15);

				for (int j = 0; j < 7; j++)
				{
					if ((j == 2) || (j == 3))
					{
						continue;
					}
					final CircleMove circleMove = new CircleMove(0.5, 0.5, j * 0.075, 0.16, 180);
					final Circle circle = new Circle(circleMove, Const.RADIUS * 0.9);
					survivalLevel.addEnemy(circle);
				}

				for (int j = 1; j < 7; j++)
				{
					if ((j == 5) || (j == 6))
					{
						continue;
					}
					final CircleMove circleMove = new CircleMove(0.5, 0.5, j * 0.075, 0.16, 180, Const.LEFT);
					final Circle circle = new Circle(circleMove, Const.RADIUS * 0.9);
					survivalLevel.addEnemy(circle);
				}

				for (int j = 1; j < 7; j++)
				{
					final CircleMove circleMove = new CircleMove(0.5, 0.5, j * 0.075, 0.08, 250);
					final Circle circle = new Circle(circleMove, Const.RADIUS * 0.9);
					survivalLevel.addEnemy(circle);
				}

				return survivalLevel;
			}
		};

		{
			index = 39;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[2];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 20;
			secondsTable[1][index] = 25;
			secondsTable[2][index] = 30;
			secondsTable[3][index] = 40;
			final int times[] =
			{ 35 };
			speedUpTimes[index] = times;
		}

		index = 40;
		// Strzelające z środka, trudniejsza wersja
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(0.9), 20, 25, 35, 60);
				survivalLevel.bounce = true;
				survivalLevel.setEnemySpawn(2, 1, radiousSizes[0]);
				final int times[] =
				{ 25, 50 };
				survivalLevel.setSpeedUpTimes(times);

				for (int i = 0; i < 2; i++)
				{
					final double radius = 1.2;
					final int howMany = 13;
					int angle = 0;
					final int step = 360 / howMany;
					for (int j = 0; j < howMany; j++)
					{
						if (i == 1)
						{
							final double x = 0.3 + (Math.cos((Math.PI * angle) / 180) * radius);
							final double y = 0.4 + (Math.sin((Math.PI * angle) / 180) * radius);
							angle += 2 * step;
							angle %= 360;
							final double targets[] =
							{ 0.3, 0.4, x, y };
							final PathMove pathMove = new PathMove(targets, Const.MAX_SPEED * 0.7);
							pathMove.setModuloMove(true);
							final int k = j / 2;
							final Circle circle = new Circle(0.3, 0 - (k * 0.4), pathMove, Const.RADIUS * 0.5);
							survivalLevel.addEnemy(circle);
						}
						else
						{
							final double x = 0.7 + (Math.cos((Math.PI * angle) / 180) * radius);
							final double y = 0.4 + (Math.sin((Math.PI * angle) / 180) * radius);
							angle += 4 * step;
							angle %= 360;
							final double targets[] =
							{ 0.7, 0.4, x, y };
							final PathMove pathMove = new PathMove(targets, Const.MAX_SPEED * 0.7);
							pathMove.setModuloMove(true);
							final int k = j / 2;
							final Circle circle = new Circle(0.7, 0 - (k * 0.4), pathMove, Const.RADIUS * 0.5);
							survivalLevel.addEnemy(circle);

						}
					}
				}
				Circle circle = new Circle(0, 0, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);
				circle = new Circle(1, 0, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);
				circle = new Circle(1, 1, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);
				circle = new Circle(0, 1, new NoMove(), Const.RADIUS);
				survivalLevel.addEnemy(circle);

				final double[] targets1 =
				{ 0.1, 0.05, 0.1, 0.95, 0.9, 0.95, 0.9, 0.05 };
				final PathMove pathMove = new PathMove(targets1, Const.MAX_SPEED * 0.5);
				circle = new Circle(0.5, 0.5, pathMove, radiousSizes[2]);
				survivalLevel.addEnemy(circle);

				return survivalLevel;
			}
		};

		index = 41;
		// Kółka lecące ze skosu, randomizowane.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final Circle player = new Circle(0.05, 0.5, new PlayerMove(), Const.RADIUS * 0.8);
				final SurvivalLevel survivalLevel = new SurvivalLevel(player, 25, 35, 45, 60);
				final int times[] =
				{ 25, 50 };
				survivalLevel.setSpeedUpTimes(times);

				for (int i = 0; i < 10; i++)
				{
					final double y = Math.random();
					final double targets[] =
					{ -0.1, y + 0.5, 1.1, y - 0.5 };
					final PathMove pathMove = new PathMove(targets, Const.MAX_SPEED / 2);
					pathMove.setModuloMove(true);
					final Circle circle = new Circle(1 + (0.1 * i), y, pathMove, Const.RADIUS * 0.8);
					survivalLevel.addEnemy(circle);
				}

				final double targets[] =
				{ 1.1, 0.05, -0.1, 0.05 };
				PathMove pathMove = new PathMove(targets, Const.MAX_SPEED / 2);
				pathMove.setModuloMove(true);
				Circle circle = new Circle(1 + 0.1, 0.05, pathMove, Const.RADIUS * 0.8);
				survivalLevel.addEnemy(circle);

				final double targets2[] =
				{ 1.1, 0.95, -0.1, 0.95 };
				pathMove = new PathMove(targets2, Const.MAX_SPEED / 2);
				pathMove.setModuloMove(true);
				circle = new Circle(1 + 0.2, 0.95, pathMove, Const.RADIUS * 0.8);
				survivalLevel.addEnemy(circle);

				circle = new Circle(0.75, 0.8, new FreeMove(Const.MAX_SPEED, Const.MAX_SPEED, survivalLevel));
				survivalLevel.addEnemy(circle);

				return survivalLevel;
			}
		};

		{
			index = 42;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			enemiesTable[index] = 6;
			radiousTable[index] = radiousSizes[1];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 40;
			secondsTable[3][index] = 60;
		}

		index = 43;
		// Survival z 1 wężykiem, trudniejsza wersja.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), 20, 25, 35, 50);
				survivalLevel.setEnemySpawn(2, 5, radiousSizes[1]);
				final int times[] =
				{ 20, 50 };
				survivalLevel.setSpeedUpTimes(times);

				double x = 0;
				final double r = 0.02;
				final Snake snake = new Snake(8);
				survivalLevel.addEnemy(snake);
				x += 0.5;
				for (int i = 7; i >= 1; i--)
				{
					final double[] targets =
					{ 0.25, 0.9 };
					final Circle circle = new Circle(x, i * 2 * r * Global.app.consts.dth, new PathMove(targets,
							Const.MAX_SPEED * 0.6), r);
					snake.addSnakeElement(circle);
				}
				return survivalLevel;
			}
		};

		index = 44;
		survivalLevels[survCount] = index;
		survCount++;
		bouncingTable[index] = true;
		wallCollision[index] = false;
		enemiesTable[index] = 7;
		radiousTable[index] = radiousSizes[0];
		spawnPeriodsTable[index] = 1;
		secondsTable[0][index] = 20;
		secondsTable[1][index] = 25;
		secondsTable[2][index] = 35;
		secondsTable[3][index] = 50;

		index = 45;
		// Kołka wirujące po całej planszy, a u góry meta chowająca się za dwoma przeciwnikami.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final PuzzleLevel puzzleLevel = new PuzzleLevel(getPlayer(), getStandardFinish(), 10, 5, 3);

				final double targets[] =
				{ 0, 0.15, 1, 0.15 };
				Circle circle = new Circle(0, 0.15, new PathMove(targets, Const.MAX_SPEED), Const.RADIUS);
				puzzleLevel.addEnemy(circle);
				circle = new Circle(0.2, 0.15, new PathMove(targets, Const.MAX_SPEED), Const.RADIUS);
				puzzleLevel.addEnemy(circle);

				final double targetsLeft[] =
				{ 0.1, 0.1, 0.1, 0.9 };
				circle = new Circle(0.1, 0.1, new PathMove(targetsLeft, Const.MAX_SPEED), Const.RADIUS);
				puzzleLevel.addEnemy(circle);
				final double targetsRight[] =
				{ 0.9, 0.1, 0.9, 0.9 };
				circle = new Circle(0.9, 0.1, new PathMove(targetsRight, Const.MAX_SPEED), Const.RADIUS);
				puzzleLevel.addEnemy(circle);

				for (int y = 1; y <= 3; y++)
				{
					for (int x = 1; x <= 3; x++)
					{
						if ((x == 2) && (y == 3))
						{
							continue;
						}
						circle = new Circle(new CircleMove(x * 0.25, y * 0.25, 0.12, 0.2, 90 * (x + y)));
						puzzleLevel.addEnemy(circle);
					}
				}

				return puzzleLevel;
			}
		};

		{
			index = 46;
			survivalLevels[survCount] = index;
			survCount++;
			bouncingTable[index] = true;
			wallCollision[index] = true;
			enemiesTable[index] = 7;
			radiousTable[index] = radiousSizes[1];
			spawnPeriodsTable[index] = 2;
			secondsTable[0][index] = 25;
			secondsTable[1][index] = 30;
			secondsTable[2][index] = 35;
			secondsTable[3][index] = 40;
			final int times[] =
			{ 30 };
			speedUpTimes[index] = times;
		}

		index = 47;
		// Przesuwające się bloki.
		levelHolders[index] = new LevelHolder()
		{
			@Override
			public Level getLevel()
			{
				final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(0.9, 0.95), 15, 30, 45, 60);
				final int times[] =
				{ 25, 45 };
				survivalLevel.setSpeedUpTimes(times);

				final double yGap = 0.08;
				final double yH = 0.12;
				double yPos = 0;
				for (int i = 0; i < 5; i++)
				{
					yPos = yGap + (i * (yH + yGap));
					final double targets[] =
					{ 0, yPos + (yH / 2), 1, yPos + (yH / 2) };
					if ((i % 2) == 1)
					{
						targets[0] = 1;
						targets[2] = 0;

						final Rectangle rectangleFirst = new Rectangle(0.5, yPos, 1, yH + yPos, new PathMove(targets,
								Const.MAX_SPEED * 0.5), Bitmaps.wallTile);
						survivalLevel.addEnemy(rectangleFirst);
					}
					else
					{
						final Rectangle rectangleFirst = new Rectangle(0, yPos, 0.5, yH + yPos, new PathMove(targets,
								Const.MAX_SPEED * 0.5), Bitmaps.wallTile);
						survivalLevel.addEnemy(rectangleFirst);
					}
				}

				final double xW1 = 0.6;
				final double targets1[] =
				{ xW1 / 2, -1, xW1 / 2, 1 };
				final double xGap1 = 0.35;
				final double targets2[] =
				{ xW1 + xGap1 + ((1 - xW1 - xGap1) / 2), -1, xW1 + xGap1 + ((1 - xW1 - xGap1) / 2), 1 };
				final PathMove pathMove1 = new PathMove(targets1, Const.MAX_SPEED * 0.5);
				pathMove1.setModuloMove(true);
				final PathMove pathMove2 = new PathMove(targets2, Const.MAX_SPEED * 0.5);
				pathMove2.setModuloMove(true);
				final Rectangle rectangleSecond = new Rectangle(0, -1, xW1, -0.95, pathMove1, Bitmaps.wallTile);
				final Rectangle rectangleThird = new Rectangle(xW1 + xGap1, -1, 1, -0.95, pathMove2, Bitmaps.wallTile);

				final double xW2 = 0.1;
				final double targets3[] =
				{ xW2 / 2, -1, xW2 / 2, 1 };
				final double targets4[] =
				{ xW2 + xGap1 + ((1 - xW2 - xGap1) / 2), -1, xW2 + xGap1 + ((1 - xW2 - xGap1) / 2), 1 };
				final PathMove pathMove3 = new PathMove(targets3, Const.MAX_SPEED * 0.5);
				pathMove3.setModuloMove(true);
				final PathMove pathMove4 = new PathMove(targets4, Const.MAX_SPEED * 0.5);
				pathMove4.setModuloMove(true);
				final Rectangle rectangleFourth = new Rectangle(0, -2, xW2, -1.95, pathMove3, Bitmaps.wallTile);
				final Rectangle rectangleFifth = new Rectangle(xW2 + xGap1, -2, 1, -1.95, pathMove4, Bitmaps.wallTile);
				survivalLevel.addEnemy(rectangleSecond);
				survivalLevel.addEnemy(rectangleThird);
				survivalLevel.addEnemy(rectangleFourth);
				survivalLevel.addEnemy(rectangleFifth);

				return survivalLevel;
			}
		};

		for (final int i : survivalLevels)
		{
			if (i == -1)
			{
				continue;
			}
			levelHolders[i] = new LevelHolder()
			{
				@Override
				public Level getLevel()
				{
					final SurvivalLevel survivalLevel = new SurvivalLevel(getPlayer(), secondsTable[0][i],
							secondsTable[1][i], secondsTable[2][i], secondsTable[3][i]);
					survivalLevel.setEnemySpawn(spawnPeriodsTable[i], enemiesTable[i], radiousTable[i]);
					survivalLevel.setBouncing(bouncingTable[i]);
					survivalLevel.setWallCollision(wallCollision[i]);

					if (speedUpTimes[i] != null)
					{
						survivalLevel.setSpeedUpTimes(speedUpTimes[i]);
					}
					return survivalLevel;
				}
			};
		}
	}
}